<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="author" content="GoJun" />
	
	
	
	<title>使用 Python 脚本将安装包上传Fir或蒲公英平台 ｜ GoJun</title>
	
    
    
    <meta name="description" content="国内知名的两大应用托管内测平台，使用 Python 脚本的方式实现安装包上传。 Fir Fir 有三种方式上传： 使用官方 Api 方式，文档 通过 fir-cli 命令行方式, 文档 Fastlane 插件方式，文档 由于 1、3 方式处理过程比较繁琐复杂，经考虑选择通过 fir-cli 命令行" />
    

    
    
    <meta name="keywords" content="Hugo, theme, zozo" />
    

	
    
    <link rel="shortcut icon" href="https://gojun.me/images/favicon.ico" />

    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.mecss/normalize.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.0/animate.min.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/zozo.css" />
	<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/highlight.css" />

    
    
</head>

<body>
    <div class="main animate__animated animate__fadeInDown">
        <div class="nav_container animated fadeInDown">
    <div class="site_nav" id="site_nav">
        <ul>
            
            <li>
                <a href="/">Home</a>
            </li>
            
            <li>
                <a href="/posts/">Archive</a>
            </li>
            
            <li>
                <a href="/tags/">Tags</a>
            </li>
            
            <li>
                <a href="/projects/">Projects</a>
            </li>
            
        </ul>
    </div>
    <div class="menu_icon">
        <a id="menu_icon"><i class="ri-menu-line"></i></a>
    </div>
</div>
        <div class="header animated fadeInDown">
    <div class="site_title_container">
        <div class="site_title">
            <h1>
                <a href="https://gojun.me">
                    <span>GoJun</span>
                </a>
            </h1>
        </div>
        <div class="description">
            <p class="sub_title">为向往生活努力奋斗！</p>
            <div class="my_socials">
                
                
                <a href="https://github.com/freelander" title="github" target="_blank"><i class="ri-github-fill"></i></a>
                
                
                <a href="https://gojun.me/index.xml" type="application/rss+xml" title="rss" target="_blank"><i
                        class="ri-rss-fill"></i></a>
            </div>
        </div>
    </div>
</div>
        <div class="content">
            <div class="post_page">
                <div class="post animate__animated animate__fadeInDown">
                    <div class="post_title post_detail_title">
                        <h2><a href='/posts/app-package-upload/'>使用 Python 脚本将安装包上传Fir或蒲公英平台</a></h2>
                        <span class="date">2022.01.23</span>
                    </div>
                    <div class="post_content markdown"><p>国内知名的两大应用托管内测平台，使用 Python 脚本的方式实现安装包上传。</p>
<h3 id="fir">Fir</h3>
<p>Fir 有三种方式上传：</p>
<ol>
<li>使用官方 Api 方式，<a href="https://www.betaqr.com/docs/publish">文档</a></li>
<li>通过 fir-cli 命令行方式, <a href="https://github.com/FIRHQ/fir-cli/blob/master/README.md#%E6%96%87%E6%A1%A3">文档</a></li>
<li>Fastlane 插件方式，<a href="https://github.com/FIRHQ/fastlane-plugin-fir_cli">文档</a></li>
</ol>
<p>由于 1、3 方式处理过程比较繁琐复杂，经考虑选择通过 fir-cli 命令行上传应用，即方式 2；</p>
<h4 id="安装-fir-cli">安装 fir-cli</h4>
<p>安装文档地址：<a href="https://github.com/FIRHQ/fir-cli/blob/master/doc/install.md">https://github.com/FIRHQ/fir-cli/blob/master/doc/install.md</a></p>
<p>这里有个比较坑的地方，按文档安装会有个报错信息：</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">(Gem::FilePermissionError)

    You don&#39;t have write permissions for the /usr/bin directory.
</code></pre></div><p><strong>注意：</strong> 即使在前面加上sudo gem install fir-cli 也没啥用。</p>
<p>需要更改一下安装目录，正确执行安装命令：</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">sudo gem install -n /usr/local/bin fir-cli
</code></pre></div><p>参考文档：<a href="https://www.jianshu.com/p/0b93a47b265c">mac系统安装fir-cli(最新有效)</a></p>
<h4 id="脚本">脚本</h4>
<div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">re</span>

<span class="n">api_token</span> <span class="o">=</span> <span class="s1">&#39;点击头像可获得 api token 信息&#39;</span>
<span class="n">file_path</span> <span class="o">=</span> <span class="s1">&#39;安装包文件路径&#39;</span>

<span class="c1"># 执行的命令</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="s1">&#39;fir p </span><span class="si">{}</span><span class="s1"> -T </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="n">api_token</span><span class="p">)</span>
<span class="c1"># python 脚本执行命令，并输出信息</span>
<span class="n">output</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>

<span class="c1"># 利用正则匹配到 fir 下载的地址及对应版本的 release id</span>
<span class="n">release_id_regex</span> <span class="o">=</span> <span class="s1">&#39;(?&lt;=Release id is )[a-zA-Z0-9_]*&#39;</span>
<span class="n">url_regex</span> <span class="o">=</span> <span class="s1">&#39;(?&lt;=Published succeed: )[a-zA-Z]+://[^\s]*&#39;</span>
<span class="n">release_id</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">release_id_regex</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="n">url</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">url_regex</span><span class="p">,</span> <span class="n">output</span><span class="p">)</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>

<span class="c1"># 拼接组合成下载地址，例如：http://d.maps9.com/59exxx?release_id=61ecdeexxxxxxx</span>
<span class="n">fir_download_url</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">{}</span><span class="s1">?release_id=</span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">release_id</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">fir_download_url</span><span class="p">)</span>

</code></pre></div><h3 id="pgyer">Pgyer</h3>
<p>蒲公英相对 Fir 来说简单很多，直接使用 Api 方式上传。</p>
<p>文档地址：<a href="https://www.pgyer.com/doc/view/api#uploadApp">https://www.pgyer.com/doc/view/api#uploadApp</a></p>
<h4 id="脚本-1">脚本</h4>
<div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>

<span class="n">file_path</span> <span class="o">=</span> <span class="s1">&#39;安装包文件路径&#39;</span>
<span class="n">api_key</span> <span class="o">=</span> <span class="s1">&#39;36ce6f5facxxxxxxxxxxxxxxxxxxx&#39;</span>

<span class="c1"># 执行的命令</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="s1">&#39;curl -F </span><span class="se">\&#39;</span><span class="s1">file=@</span><span class="si">{}</span><span class="se">\&#39;</span><span class="s1"> -F </span><span class="se">\&#39;</span><span class="s1">_api_key=</span><span class="si">{}</span><span class="se">\&#39;</span><span class="s1"> https://www.pgyer.com/apiv2/app/upload&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="n">api_key</span><span class="p">)</span>
<span class="c1"># 执行命令并输出信息</span>
<span class="n">output</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>

<span class="c1"># 上传成功之后是返回一段 json 字符串，将其转换成 json</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
<span class="c1"># 获取 build key</span>
<span class="n">build_key</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;buildKey&#39;</span><span class="p">]</span>
<span class="n">pgyer_download_url</span> <span class="o">=</span> <span class="s1">&#39;https://www.pgyer.com/</span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">build_key</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">pgyer_download_url</span><span class="p">)</span>
</code></pre></div></div>
                    <div class="post_footer">
                        
                        <div class="meta">
                            <div class="info">
                                <span class="field tags">
                                    <i class="ri-stack-line"></i>
                                    
                                    <a href="https://gojun.me/tags/python/">Python</a>
                                    
                                    <a href="https://gojun.me/tags/fir/">Fir</a>
                                    
                                    <a href="https://gojun.me/tags/pgyer/">Pgyer</a>
                                    
                                </span>
                            </div>
                        </div>
                        
                    </div>
                </div>
                
                
                <div class="doc_comments"></div>
                
            </div>
        </div>
    </div>
    <a id="back_to_top" href="#" class="back_to_top"><i class="ri-arrow-up-s-line"></i></a>
    <footer class="footer">
    <div class="footer_slogan">
        <span></span>
    </div>
</footer>
    <script src="https://gojun.me/js/jquery-3.5.1.min.js"></script>
<link href="https://gojun.me/css/fancybox.min.css" rel="stylesheet">
<script src="https://gojun.me/js/fancybox.min.js"></script>
<script src="https://gojun.me/js/zozo.js"></script>


<script type="text/javascript" async
    src="https://cdn.bootcss.com/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
        MathJax.Hub.Config({
            tex2jax: {
                inlineMath: [['$', '$'], ['\\(', '\\)']],
                displayMath: [['$$', '$$'], ['\[\[', '\]\]']],
                processEscapes: true,
                processEnvironments: true,
                skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
                TeX: {
                    equationNumbers: { autoNumber: "AMS" },
                    extensions: ["AMSmath.js", "AMSsymbols.js"]
                }
            }
        });

        MathJax.Hub.Queue(function () {
            
            
            
            var all = MathJax.Hub.getAllJax(), i;
            for (i = 0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

<style>
    code.has-jax {
        font: inherit;
        font-size: 100%;
        background: inherit;
        border: inherit;
        color: #515151;
    }
</style>



<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'UA-142037913-1', 'auto');
	
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>

</body>

</html>